﻿using myBackupClient.Backup;
using myBackupClient.Model;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using TouchSocket.Core;
using TouchSocket.Http;
using TouchSocket.Sockets;
namespace myBackupClient
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }
        private HttpClient _httpClien = null;
        private string _backupSaveRootPath = BackupConfig.Instance.BackupSaveRootPath;
        private async Task Backup(string destinationCatalog,string url)
        {
         
            try
            {
                HttpClient httpClient = await GetHttpClient();
                var body = await httpClient.GetStringAsync(url);
                XElement xElement = XElement.Parse(body);
                var xElementDirectorys = xElement.Elements("Directory");
                foreach (var item in xElementDirectorys)
                { 
                    var pathId = item.Attribute("PathId").Value;
                    var sourceCatalog = item.Attribute("Name").Value;
                    List<string> failFiles = new List<string>();
                    var addedFiles = new HashSet<DirectoryFileInfo>();
                    var deletedFiles = new HashSet<DirectoryFileInfo>();
                    var modifiedFiles = new HashSet<DirectoryFileInfo>();
                    var addedDirs = new HashSet<DirectoryFileInfo>();
                    var deletedDirs = new HashSet<DirectoryFileInfo>();
                    CompareFolders.Compare(item, _backupSaveRootPath, sourceCatalog, out addedFiles, out deletedFiles, out modifiedFiles, out addedDirs, out deletedDirs);
                    Func<DirectoryFileInfo, Task<bool>> downloadFile = async (filePath) =>
                    {
                        string sourceFileName = filePath.Path;
                        string destFileName = Path.Combine(_backupSaveRootPath, filePath.Path);
                        int i = 1;
                        while (i <= 3)
                        {
                            try
                            {
                                string dirPath = Path.GetDirectoryName(destFileName);
                                if (!System.IO.Directory.Exists(dirPath))
                                {
                                    System.IO.Directory.CreateDirectory(dirPath);
                                }
                                if (File.Exists(destFileName))
                                    File.Delete(destFileName);
                                var isSuccess = false;
                                using (var stream = File.Create(destFileName))
                                {
                                    using (CancellationTokenSource cts2 = new CancellationTokenSource())
                                    {
                                        var flowOperator = new BackupFileHttpFlowOperator()
                                        {
                                            Token = cts2.Token
                                        };
                                        flowOperator.ProgressChanged += (progress, speed) =>
                                        {
                                            this.BeginInvoke((Action)(() =>
                                            {
                                                this.toolStripStatusLabel.Text = $"正在同步：{destFileName} 进度：{Math.Round(progress * 100, 2)}% 速度：{ConvertFileSize(speed)}/秒";
                                            }));

                                        };
                                        httpClient = await GetHttpClient();
                                        var result = await httpClient.GetFileAsync("/Download?pathId=" + pathId + "&path=" + sourceFileName, stream, flowOperator);
                                        isSuccess = result.IsSuccess;
                                        this.BeginInvoke((Action)(() =>
                                        {
                                            this.toolStripStatusLabel.Text = $"就绪";
                                        }));
                                    }
                                }
                                if(!isSuccess)
                                {
                                    if (File.Exists(destFileName))
                                        File.Delete(destFileName);
                                    await Task.Delay(1000 * i);
                                }
                                if(File.Exists(destFileName))
                                {
                                    FileInfo fileInfo = new FileInfo(destFileName);
                                    fileInfo.CreationTime = filePath.CreationTime;
                                    fileInfo.LastWriteTime = filePath.LastWriteTime;
                                    break;
                                }
                                
                            }
                            catch (Exception ex)
                            { 
                                await Task.Delay(1000 * i);
                            }
                            finally
                            {
                                i++;
                            }
                        }
                        string msg = sourceFileName + " 同步到 " + destFileName + ",时间：" + DateTime.Now;
                        if (i <= 3)
                        {
                            msg = "成功：" + msg;
                        }
                        else
                        {
                            msg = "失败：" + msg;
                        }
                        this.BeginInvoke((Action)(() =>{  this.richTextBox.AppendText(msg+"\r\n") ;}));
                        return i <= 3;
                    };
                    Func<DirectoryFileInfo, Task<bool>> deleteFile =  async(filePath) =>
                    {
                        string path = Path.Combine(_backupSaveRootPath, filePath.Path);
                        int i = 1;
                        while (i <= 3)
                        {
                            try
                            {
                                if (!System.IO.File.Exists(path))
                                {
                                    return true;
                                }
                                System.IO.File.Delete(path);
                                break;
                            }
                            catch (Exception)
                            {
                                await Task.Delay(1000 * i);
                            }
                            finally
                            {
                                i++;
                            }
                        }
                        string msg = path + "删除" + ",时间：" + DateTime.Now; ;
                        if (i <= 3)
                        {
                            msg = "成功：" + msg;
                        }
                        else
                        {
                            msg = "失败：" + msg;
                        }
                        this.Invoke((Action)(() => { this.richTextBox.AppendText(msg + "\r\n"); }));
                        return i <= 3;
                    };
                    Func<DirectoryFileInfo, Task<bool>> createDirectory = async (filePath) =>
                    {
                        int i = 1;
                        while (i <= 3)
                        {
                            try
                            {
                                string path = Path.Combine(_backupSaveRootPath, filePath.Path);
                                if (System.IO.Directory.Exists(path))
                                {
                                    break;
                                }
                                System.IO.Directory.CreateDirectory(path);
                            }
                            catch (Exception)
                            {
                                await Task.Delay(1000 * i);
                            }
                            finally
                            {
                                i++;
                            }
                        }
                        if (i <= 3)
                        {
                            //成功
                        }
                        else
                        {
                            //失败
                        }
                        return i <= 3;
                    };
                    Func<DirectoryFileInfo, Task<bool>> deleteDirectory = async (filePath) =>
                    {
                        int i = 1;
                        while (i <= 3)
                        {
                            try
                            {
                                string path = Path.Combine(_backupSaveRootPath,  filePath.Path);
                                if (!System.IO.Directory.Exists(path))
                                {
                                    break;
                                }
                                System.IO.Directory.Delete(path, true);
                            }
                            catch (Exception)
                            {
                                await Task.Delay(1000 * i);
                            }
                            finally
                            {
                                i++;
                            }
                        }
                        if (i <= 3)
                        {
                            //成功
                        }
                        else
                        {
                            //失败
                        }
                        return i <= 3;
                    };
                    foreach (var deletedFile in deletedFiles)//删除文件
                    {
                        await deleteFile(deletedFile);
                    }
                    foreach (var addedFile in addedFiles)//新增文件
                    {
                        await downloadFile(addedFile);
                    }
                    foreach (var modifiedFile in modifiedFiles)//修改文件
                    {
                        await downloadFile(modifiedFile);
                    }
                    foreach (var deletedDir in deletedDirs)//删除文件夹
                    {
                        await deleteDirectory(deletedDir);
                    }
                    foreach (var addedDir in addedDirs)//新增文件夹
                    {
                        await createDirectory(addedDir);
                    }
                    var directoryElements= item.Elements("Directory");
                    foreach (var directoryElement in directoryElements)
                    {
                        var name= directoryElement.Attribute("Name").Value.Trim('\\');
                        var subSourceCatalog =Path.Combine(sourceCatalog, name);
                        var subDestinationCatalog = Path.Combine(_backupSaveRootPath, sourceCatalog);
                        await Backup(Path.Combine(subDestinationCatalog, sourceCatalog), "/GetCatalog?pathId=" + pathId + "&maxDepth=1&path="+ subSourceCatalog);
                    }
                }
            }
            catch (Exception ex)
            {
                await Backup(destinationCatalog, url);
            }
        }

  
        private  async Task<HttpClient> GetHttpClient()
        {
            if (_httpClien != null)
                _httpClien.SafeDispose();
            _httpClien = new HttpClient();
            var config = new TouchSocketConfig();
            config.SetRemoteIPHost(BackupConfig.Instance.IpPort).ConfigureContainer(a=>a.AddConsoleLogger());
            await _httpClien.SetupAsync(config);
            await _httpClien.ConnectAsync();
            return _httpClien;
        }
        public static string ConvertFileSize(long size)
        {
            long kb = 1024;
            long mb = kb * 1024;
            long gb = mb * 1024;
            if (size >= gb)
            {
                return $"{((float)size / gb).ToString("0.##")}GB";
            }
            else if (size >= mb)
            {
                long f = (long)size / mb;
                return string.Format(f > 100 ? "{0}MB" : "{0}MB", decimal.Round(f, 2));
            }
            else if (size >= kb)
            {
                long f = (long)size / kb;
                return string.Format(f > 100 ? "{0}KB" : "{0}KB", decimal.Round(f, 2));
            }
            else
                return $"{size}B";
        }
        private void frmMain_Load(object sender, EventArgs e)
        {

        }
        private async void btn_synchronize_Click(object sender, EventArgs e)
        {
            await Backup(_backupSaveRootPath, "/GetCatalog?maxDepth=1");
        }

        private void btn_setting_Click(object sender, EventArgs e)
        {
            frmSetting frmSetting = new frmSetting();
            frmSetting.ShowDialog();
        }
    }
}
